# Author: Mr.Xu
# @Time : 2019/11/30 17:44
from rest_framework import serializers
import re
from rest_framework_jwt.serializers import jwt_payload_handler
from rest_framework_jwt.serializers import jwt_encode_handler
from django.core.cache import cache
from django.conf import settings
from . import models

# 多方式登陆并签发token
class LoginModelSerializer(serializers.ModelSerializer):
    username = serializers.CharField(write_only=True)
    password = serializers.CharField(write_only=True)

    class Meta:
        model = models.User
        fields = ["username", "password"]

    def validate_username(self,username):
        if not username:
            raise serializers.ValidationError("用户名不合法")
        return username

    # 在全局钩子中签发token
    def validate(self, attrs):
        # user = authenticate(**attrs)
        # 账号密码登录 => 多方式登录
        user = self._many_method_login(**attrs)

        # 签发token，并将user和token存放到序列化对象中
        payload = jwt_payload_handler(user)  # 使用jwt认证模块，根据当前用户得到载荷
        token = jwt_encode_handler(payload)  # 使用jwt认证模块，得到token

        self.user = user
        self.token = token

        return attrs

    # 多方式登录
    def _many_method_login(self, **attrs):
        username = attrs.get('username')
        password = attrs.get('password')
        # 邮箱登陆
        if re.match(r'.*@.*', username):
            user = models.User.objects.filter(email=username).first()
        # 手机号登陆
        elif re.match(r'^1[3-9][0-9]{9}$', username):
            user = models.User.objects.filter(mobile=username).first()
        # 账号密码登陆
        else:
            user = models.User.objects.filter(username=username).first()
        # 用户校验
        if not user:
            raise serializers.ValidationError({'username': '账号有误'})
        # 密码校验
        if not user.check_password(password):
            raise serializers.ValidationError({'password': '密码有误'})

        return user


# 注册
class RegisterModelSerializer(serializers.ModelSerializer):
    code = serializers.CharField(write_only=True)
    class Meta:
        model = models.User
        fields = ["mobile", 'password', "code"]


    def validate_mobile(self, value):
        if re.match(r'^1[3-9][0-9]{9}$', value):
            return value
        raise serializers.ValidationError('手机号格式有误')


    def validate_code(self, value):
        try:
            int(value)
            return value
        except:
            raise serializers.ValidationError('验证码格式有误')


    def validate_password(self, value):
        # 密码不能包含或必须包含哪些字符
        return value


    def validate(self, attrs):
        mobile = attrs.get("mobile")
        code = attrs.pop("code")

        # 获取缓存数据库的验证码
        if cache.get(f"{settings.SMS_CACHE_KEY}{mobile}") != code:
            raise serializers.ValidationError({"code": "验证码错误"})

        # 数据库存储
        attrs["username"] = mobile

        # # 为了保证验证码安全，验证码验证成功后，失效
        # cache.set(f"{settings.SMS_CACHE_KEY}{mobile}", '0000', 0)

        return attrs

    # 重写create方法，通过create_user创建用户，否则就是明文的
    def create(self, validated_data):
        return models.User.objects.create_user(**validated_data)



# 验证码登陆并签发token
class CodeLoginModelSerializer(serializers.ModelSerializer):
    mobile = serializers.CharField(write_only=True)
    code = serializers.CharField(write_only=True)

    class Meta:
        model = models.User
        fields = ["mobile", "code"]


    def validate_mobile(self, value):
        if re.match(r'^1[3-9][0-9]{9}$', value):
            return value
        raise serializers.ValidationError('手机号格式有误')


    def validate_code(self, value):
        try:
            int(value)
            return value
        except:
            raise serializers.ValidationError('验证码格式有误')

    # 在全局钩子中签发token
    def validate(self, attrs):
        user = self._code_method_login(**attrs)

        # 签发token，并将user和token存放到序列化对象中
        payload = jwt_payload_handler(user)  # 使用jwt认证模块，根据当前用户得到载荷
        token = jwt_encode_handler(payload)  # 使用jwt认证模块，得到token

        self.user = user
        self.token = token

        return attrs

    # 验证码登录
    def _code_method_login(self, **attrs):
        mobile = attrs.get('mobile')
        code = attrs.get('code')
        # 查询手机号
        user = models.User.objects.filter(mobile=mobile).first()

        # 用户校验
        if not user:
            raise serializers.ValidationError({'mobile': '手机号有误'})
        # 验证码校验
        if cache.get(f"{settings.SMS_CACHE_KEY}{mobile}") != code:
            raise serializers.ValidationError({"code": "验证码错误"})

        # 为了保证验证码安全，验证码验证成功后，失效
        cache.set(f"{settings.SMS_CACHE_KEY}{mobile}", '0000', 0)

        return user

